<script setup lang="ts">
  // @ts-ignore
  import { isString, isNumber, INJECTION_SYMBOL_PANE_LENGTH_PERCENT, INJECTION_SYMBOL_IS_MOVING } from '@/utils';

  const props = defineProps({
    direction: {
      type: String,
      default: 'row',
    },
    // 区域一所占整体百分比
    paneLengthPercent: {
      type: [Number, String],
      default: '50%',
      required: true,
    },
    triggerLength: {
      type: [Number, String],
      default: '10px',
    },
    min: {
      type: String,
    },
    max: {
      type: String,
    },
  });

  const emit = defineEmits(['update:pane-length-percent']);
  const { direction, paneLengthPercent, triggerLength, min, max } = toRefs(props);
  provide(INJECTION_SYMBOL_PANE_LENGTH_PERCENT, paneLengthPercent);

  // 鼠标距滑动器左侧(上侧)的偏移距离
  const triggerLeftOffset = ref<Number>(0);
  const splitPaneRef = ref<null | Element>(null);
  const isMoving = ref(false);
  provide(INJECTION_SYMBOL_IS_MOVING, isMoving);

  const processedPaneLengthPercent = computed(() => {
    const percent = paneLengthPercent.value;
    if (!isNumber(percent) && !isString(percent)) {
      throw new Error('paneLengthPercent value must be type of string or number');
    }

    if (isNumber(percent)) {
      return `${percent}%`;
    }

    if (isString(percent)) {
      if (percent.endsWith('%')) {
        return percent;
      } else {
        throw new Error('paneLengthPercent value must be type of string and end up with %');
      }
    }
  });
  const processedTriggerLength = computed(() => {
    const length = triggerLength.value;
    if (!isNumber(length) && !isString(length)) {
      throw new Error('triggerLength value must be type of string or number');
    }

    if (isNumber(length)) {
      return `${length}px`;
    }

    if (isString(length)) {
      if (length.endsWith('px')) {
        return length;
      } else {
        throw new Error('triggerLength value must be type of string and end up with px');
      }
    }

    return '0px';
  });
  const paneLengthValue = computed(() => `calc(${processedPaneLengthPercent.value} - ${parseFloat(processedTriggerLength.value) / 2}px)`);
  const processedMin = computed(() => {
    const m = min!.value;
    if (m) {
      if (isString(m)) {
        if (m.endsWith('%')) {
          return parseFloat(m);
        } else {
          throw new Error('min value must be type of string and end up with %');
        }
      }
    }
    return m;
  });
  const processedMax = computed(() => {
    const m = max!.value;
    if (m) {
      if (isString(m)) {
        if (m.endsWith('%')) {
          return parseFloat(m);
        } else {
          throw new Error('max value must be type of string and end up with %');
        }
      }
    }
    return m;
  });

  const onMouseDown = (e: MouseEvent) => {
    // 事件绑定
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);

    // 计算逻辑始终认为鼠标在滑动器的正中间
    if (direction.value === 'row') {
      // Event.srcElement 是标准的 Event.target 属性的一个别名。 该特性是非标准的，请尽量不要在生产环境中使用它！
      triggerLeftOffset.value = e.pageX - e.target.getBoundingClientRect().left;
    } else if (direction.value === 'column') {
      triggerLeftOffset.value = e.pageY - e.target.getBoundingClientRect().top;
    }
  };
  const onMouseMove = (e: MouseEvent) => {
    const clientRect = splitPaneRef.value?.getBoundingClientRect();
    let paneLengthPercent = 0;

    if (direction.value === 'row') {
      const offset = e.pageX - clientRect.left - triggerLeftOffset.value + parseFloat(triggerLength.value) / 2;
      paneLengthPercent = (offset / clientRect.width) * 100;
    } else if (direction.value === 'column') {
      const offset = e.pageY - clientRect.top - triggerLeftOffset.value + parseFloat(triggerLength.value) / 2;
      paneLengthPercent = (offset / clientRect.width) * 100;
    }

    if (processedMin.value && paneLengthPercent < processedMin.value) {
      paneLengthPercent = processedMin.value;
    }
    if (processedMax.value && paneLengthPercent > processedMax.value) {
      paneLengthPercent = processedMax.value;
    }

    isMoving.value = true;
    emit('update:pane-length-percent', `${paneLengthPercent}%`);
  };
  const onMouseUp = () => {
    isMoving.value = false;
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
  };
</script>

<template>
  <div :class="['split-pane', direction === 'row' ? 'row-direction' : 'column-direction']" ref="splitPaneRef">
    <div :class="['pane pane-one', direction === 'row' ? 'row-direction' : 'column-direction']">
      <slot name="pane-one"></slot>
    </div>
    <div :class="['pane-trigger-wrapper', direction === 'row' ? 'row-direction' : 'column-direction']" @mousedown="onMouseDown">
      <slot name="pane-trigger">
        <div class="pane-trigger"></div>
      </slot>
    </div>
    <div :class="['pane pane-two', direction === 'row' ? 'row-direction' : 'column-direction']">
      <slot name="pane-two"></slot>
    </div>
  </div>
</template>

<style scoped lang="scss">
  .split-pane {
    display: flex;
    width: 100%;
    height: 100%;

    &.row-direction {
      flex-direction: row;
    }

    &.column-direction {
      flex-direction: column;
    }

    .pane-one {
      &.row-direction {
        width: v-bind(paneLengthValue);
        height: 100%;
      }

      &.column-direction {
        width: 100%;
        height: v-bind(paneLengthValue);
      }
    }

    .pane-trigger-wrapper {
      // 在拖动过程中，如果区域中有文字内容可能会出现选中文字的情况，给滑动器添加禁止选中效果。
      user-select: none;
      // background: palegoldenrod;
      /*拖拽区鼠标悬停样式*/
      &:hover {
        color: orange;
      }

      &.row-direction {
        height: 100%;
        cursor: col-resize;
        .pane-trigger,
        > * {
          width: v-bind(processedTriggerLength);
          height: 100%;
        }
      }

      &.column-direction {
        width: 100%;
        cursor: row-resize;
        .pane-trigger,
        > * {
          width: 100%;
          height: v-bind(processedTriggerLength);
        }
      }
    }

    .pane-two {
      flex: 1;

      &.row-direction {
        width: 0;
        height: 100%;
      }

      &.column-direction {
        width: 100%;
        height: 0;
      }
    }
  }
</style>
